package cn.anquing.demo.mybatisplus.component.mybatisconfig;

import com.baomidou.mybatisplus.annotation.SqlParser;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.core.parser.ISqlParser;
import com.baomidou.mybatisplus.core.parser.ISqlParserFilter;
import com.baomidou.mybatisplus.core.parser.SqlParserHelper;
import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
//import com.baomidou.mybatisplus.extension.parsers.DynamicTableNameParser;
import com.baomidou.mybatisplus.extension.parsers.DynamicTableNameParser;
import com.baomidou.mybatisplus.extension.parsers.ITableNameHandler;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParser;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;

/**
 * @author gdsunfly_wangquanqing
 * @date 2019/4/19 17:50
 */
@Configuration
public class MybatisConfig {

    public static ThreadLocal<String> myTableName = new ThreadLocal<>();
    
    /**
     * 性能分析插件，通常在开发、测试环境下开启
     * mybatis-plus-boot-starter在3.2.0版本的更新日志提到     *
     * "移除 PerformanceInterceptor 相关
     *
     * <p>performanceInterceptor.
     *
     * @author wangqq65
     * @since 2022/5/6 16:55
     * @param 
     * @return 
     */
    @Bean
//    @Profile({"test","dev"})
    public PerformanceInterceptor performanceInterceptor(){
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        // 格式化
        performanceInterceptor.setFormat(true);
        // 设置最大执行时长
        performanceInterceptor.setMaxTime(1000L);
        return performanceInterceptor;
    }


    /**
     * 版本号拦截器
     *
     */
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }

    /**
     * 分页插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();

        // 一、多租户（查询及其他操作都会带上租户ID，自定义多表查询的，一定要给表设置**别名**）
        ArrayList<ISqlParser> iSqlParsers = new ArrayList<>();
        TenantSqlParser tenantSqlParser = new TenantSqlParser();
        tenantSqlParser.setTenantHandler(new TenantHandler() {
            @Override
            public Expression getTenantId() {
                // 正常是从ThreadLocal中获取当前租户ID，这里先写死
                return new LongValue("1087982257332887553");
            }

            @Override
            public String getTenantIdColumn() {
                return "manager_id";
            }

            @Override
            public boolean doTableFilter(String tableName) {
                // 过滤特定表
                if ("demo".equals(tableName)){
                    return true;
                }
                return false;
            }
        });
        iSqlParsers.add(tenantSqlParser);

        // 二、过滤特定方法1：
        paginationInterceptor.setSqlParserFilter(new ISqlParserFilter() {
            @Override
            public boolean doFilter(MetaObject metaObject) {
                MappedStatement mappedStatement = SqlParserHelper.getMappedStatement(metaObject);
                if ("cn.anquing.demo.mybatisplus.code.dao.UserDao.selectById".equals(mappedStatement.getId())) {
                    return true;
                }
                return false;
            }
        });
        // 过滤特定方法2：在dao接口中添加注解@SqlParser(filter = true)
        // 3.1.1 之前的版本要添加配置 sql-parser-cache: true

        // 三、动态表名(要求3.1.2版本及更高,过滤了多租户方法不生效)
        DynamicTableNameParser dynamicTableNameParser = new DynamicTableNameParser();
        HashMap<String, ITableNameHandler> tableNameHandlerMap = new HashMap<>(16);
        tableNameHandlerMap.put("user", new ITableNameHandler() {
            @Override
            public String dynamicTableName(MetaObject metaObject, String sql, String tableName) {
                return myTableName.get();
            }
        });
        dynamicTableNameParser.setTableNameHandlerMap(tableNameHandlerMap);
        iSqlParsers.add(dynamicTableNameParser);
        paginationInterceptor.setSqlParserList(iSqlParsers);
        return paginationInterceptor;
    }

    /**
     * 逻辑删除，官方说3.1.1版本及以后不需要
     */
//    @Bean
//    public ISqlInjector sqlInjector() {
//        return new LogicSqlInjector();
//    }

    /**
     * 对公共字段的填充
     */
    @Component
    public static class MetaObjectHandlerConfig  implements MetaObjectHandler {

        /**
         * 插入元对象字段填充（用于插入时对公共字段的填充）
         *
         * @param metaObject 元对象
         */
        @Override
        public void insertFill(MetaObject metaObject) {
            if (metaObject.hasSetter("createTime")){
                this.setInsertFieldValByName("createTime", LocalDateTime.now(), metaObject);
            }
            if (metaObject.hasSetter("updateTime")){
                this.setInsertFieldValByName("updateTime", LocalDateTime.now(), metaObject);
            }
        }

        /**
         * 更新元对象字段填充（用于更新时对公共字段的填充）
         *
         * @param metaObject 元对象
         */
        @Override
        public void updateFill(MetaObject metaObject) {
            if (metaObject.hasSetter("updateTime")){
                this.setUpdateFieldValByName("updateTime", LocalDateTime.now(), metaObject);
            }
        }
    }


}
